import { Object3D } from "../../entity/Object3D";
import { Mesh } from "../../component/Mesh";
import { Geometry } from "../../geom/Geometry";
import { StandardMaterial } from "../../material/StandardMaterial";
import { getTexturesObject } from "./gltf/util";
import { Matrix4 } from "../../core/math/Matrix4";
import { Quaternion } from "../../core/math/Quaternion";
import { Euler } from "../../core/math/Euler";
import { Vector3 } from "../../core/math/Vector3";
import { Matrix3 } from "../../core/math/Matrix3";
import { isNotBlank, randomString } from "../../core/utils";
import { process } from "../../process/worker/process";
import { Animation, Channel, Sampler, tween } from "../../component/animation/index";
import { any } from "../../core/logic";
import { AnimationSystem } from "../../system/AnimationSystem";
import { Engine } from "../../Engine";
import { Trans } from "../../component/index";
import { DBHelper } from "../indexdb/DBHelper";
import { Box3 } from "../../core/math/Box3";
const aniMix = new AnimationSystem();

/**
 * GLTF加载器类，用于加载GLTF资源
 * @class
 * @memberof w.loader
 * @example
 *  let loader = new w.loader.GLTFLoader();//创建加载器。
 *  let loader=engine.res.gltfLoader;//使用引擎内置加载器。
 *  loader.load('http://127.0.0.1/demo/assets/testmodel/ljjc.gltf',{back:true}, (gltf) => {
 *   gltf.rotateX((Math.PI * 90) / 180);
 *   gltf.scale = [0.1, 0.1, 0.1];
 *   scene.add(gltf);
 *  });
 */
class GLTFLoader {
  /**
   * 创建一个GLTF加载器实例。
   * @constructor
   */
  constructor(opts = {}) {
    this._fetchConfig = { credentials: "omit" };
    this.lastReadBytes = 0;
    this.lastWriteBytes = 0;
    this.materialMap = new Map();
    this.nodes = new Map();
    this.worldMatrix = new Matrix4();
    this.meshMap = new Map();
    this.animations = new Map();
    this.skinAnmations = new Map();
    this.ll = new Set();
    this.boxEnable = any(opts.boxEnable, false);
    if (this.boxEnable) {
      this.boundingBox = new Box3(new Vector3(Infinity, Infinity, Infinity), new Vector3(-Infinity, -Infinity, -Infinity))
    }

  }
  /**
   * 加载GLTF资源。
   * @method
   * @param {String} url GLTF资源路径。
   * @param {*} opts 
   * @param {Array} opts.position【可选,缺省:undefine】模型初始化位置。
   * @param {Array} opts.scale【可选,缺省:undefine】模型初始化缩放。
   * @param {Array} opts.rotation 【可选,缺省:undefine】模型初始化旋转。
   * @param {Array} opts.instances 【可选,缺省:undefine】实例化值。
   * @param {Number} opts.maxInstanceNum 【可选,缺省:1】实例化的数量。
   * @param {Boolean} opts.indexedDB 【可选,缺省:false】 是否存储到IndexDB。
   * @param {Boolean} opts.back 【可选,缺省：true】是否后台加载,开启则会在webworker中执行。
   * @param {Boolean} opts.optimize 【可选,缺省false】是否性能优化，缺省：false，开启后性能更高，但是代价是去掉了gltf模型图元的父子结构。
   * @example
   * //实例化加载
   * loader.load(url,{instance:[{position:[1,0,0],scale:[1,1,1],rotation:[Math.PI/2,0,0]},{position:[2,0,0],scale:[1,1,1],rotation:[Math.PI/2,0,0]}]});
   * //非实例化加载
   * loader.load(url,{position:[1,0,0],scale:[1,1,1],rotation:[Math.PI/2,0,0]});
   * @param {Function} callback GLTF资源加载后回调函数。
   */
  async load(url, opts, callback) {
    const back = any(opts.back, true);
    const optimize = any(opts.optimize, false);
    const indexedDB = any(opts.indexedDB, false);
    const mipMap = any(opts.mipMap, true);
    const bigTextureQuality = any(opts.bigTextureQuality, 1.0);
    opts.instances = any(opts.instances, []);
    let instances = []; //每次加载先置为空数组
    if (opts.instances) {
      instances = opts.instances;
    }
    let maxInstanceNum = any(opts.maxInstanceNum, 1);
    maxInstanceNum = Math.max(maxInstanceNum, instances.length);
    let db = null;
    if (indexedDB) {
      db = await DBHelper.getInstance().openPromise("gltf");
    }
    var results = url.split("/");
    let fileName = results.slice(results.length - 1, results.length).toString();
    let localMatrix = new Matrix4();
    if (maxInstanceNum > 1) {
      instances = opts.instances;
    } else {
      let position = any(opts.position, [0, 0, 0]);
      let rotation = any(opts.rotation, [0, 0, 0]);
      const rotateE = new Euler(rotation[0], rotation[1], rotation[2], "XYZ");
      let scale = any(opts.scale, [1, 1, 1]);
      instances.push({ position, rotation, scale });
      localMatrix.makeRotationFromEuler(rotateE);
      localMatrix.scale(new Vector3(...scale));
      localMatrix.setPosition(...position);
    }

    const engine = Engine.instance;
    this.engine = engine;
    const supportedFormatList = engine.supportedFormatList;
    if (indexedDB) {
      const event = await db.getPromise(url);
      const result = event.result;
      if (result) {
        const gltf = result.value;
        let id = fileName; //根节点id
        this.animations.set(id, []);
        this.skinAnmations.set(id, []);
        if (gltf.noAnimation && optimize) {
          this.createMaterial(gltf, mipMap, bigTextureQuality);
          const primitives = gltf.primitives;
          let meshes = [];
          const root = new Object3D({ id: id });
          for (let index = 0; index < primitives.length; index++) {
            const element = primitives[index];
            const geometry = new Geometry();
            if (element.geometry.position) {
              geometry["position"] = element.geometry.position;
              // geometry["position1"] = element.geometry.position;
            }
            if (element.geometry.indices) {
              geometry["indices"] = element.geometry.indices;
            }
            if (element.geometry.normal) {
              geometry["normal"] = element.geometry.normal;
              // geometry["normal1"] = element.geometry.normal;
            }
            if (element.geometry.texCood1) {
              geometry["texCood1"] = element.geometry.texCood1;
            }
            if (element.geometry.texCood0) {
              geometry["texCood0"] = element.geometry.texCood0;
            }
            if (element.geometry.color) {
              geometry["color"] = new Uint8Array(element.geometry.color);
            }
            if (element.geometry.tangents) {
              geometry["tangent"] = element.geometry.tangents;
              // geometry["tangent1"] = element.geometry.tangents;
            }
            if (element.geometry.targets) {
              geometry.morphTargets = element.geometry.morphTargets;
            }

            let standardMaterial = this.materialMap.get(element.material);
            if (!standardMaterial) {
              standardMaterial = new StandardMaterial({ metallicRoughnessMap: null });
            }
            const meshCom = new Mesh({ geometry, material: standardMaterial });
            const primitive = new Object3D({ maxInstanceNum });
            primitive.addComponent(meshCom);
            if (maxInstanceNum > 1) {
              for (let index = 0; index < instances.length; index++) {
                const instanceData = instances[index]; //{position:[],scale:[],rotation:[]}
                if (index == 0) {
                  //索引为0的时候应该是改
                  const trans = primitive.trans.getInstance(0);
                  instanceData.position && (trans.position = instanceData.position);
                  instanceData.scale && (trans.scale = instanceData.scale);
                  instanceData.rotation && (trans.rotation = instanceData.rotation);
                  trans.applyMatrix4(element.worldMatrix);
                } else {
                  //其他是增加
                  const trans = new Trans(instanceData);
                  trans.applyMatrix4(element.worldMatrix);
                  primitive.trans.add(trans);
                }
              }
            } else {
              primitive.trans.applyMatrix4(element.worldMatrix);
            }

            root.add(primitive);
          }
          callback(root);
        } else {
          let root = new Object3D({ id });
          if (maxInstanceNum <= 1) {
            //非实例化
            root.trans.applyMatrix4(localMatrix);
          }
          this.materialMap = new Map();
          this.geometryMeshes = [];
          this.createMaterial(gltf, mipMap, bigTextureQuality);
          this.createGeometryMesh(gltf, id);
          let children = [];
          gltf.scenes[gltf.defaultScene].nodes.map(child => {
            let id = root.id + `${child}`;
            children.push(id);
            const node = this.parseNode(child, root, gltf, null, instances, maxInstanceNum);
            // root.add(node)
            this.nodes.set(child, node);
          });
          // rootNode.children = children;
          if (gltf.animations && gltf.animations.length) {
            this.handleAnimation(gltf.animations, id);
          }
          callback(root);
          // root.update();
        }
      } else {
        process({ url, type: "gltf", back, matrix: localMatrix, optimize, supportedFormatList },
          async message => {
            //todo 子线程处理完成后，执行主线程的操作
            // sRGB空间转为线性空间
            let gltf = message.data;
            // console.log(gltf);
            // let id = fileName + `${gltf.defaultScene}` + randomString(4); //根节点id
            let id = fileName; //根节点id
            this.animations.set(id, []);
            this.skinAnmations.set(id, []);
            if (gltf.noAnimation && optimize) {
              this.createMaterial(gltf, mipMap, bigTextureQuality);
              const primitives = gltf.primitives;
              let meshes = [];
              const root = new Object3D({ id: id });
              for (let index = 0; index < primitives.length; index++) {
                const element = primitives[index];
                const geometry = new Geometry();
                if (element.geometry.position) {
                  geometry["position"] = element.geometry.position;
                  // geometry["position1"] = element.geometry.position;
                }
                if (element.geometry.indices) {
                  geometry["indices"] = element.geometry.indices;
                }
                if (element.geometry.normal) {
                  geometry["normal"] = element.geometry.normal;
                  // geometry["normal1"] = element.geometry.normal;
                }
                if (element.geometry.texCood1) {
                  geometry["texCood1"] = element.geometry.texCood1;
                }
                if (element.geometry.texCood0) {
                  geometry["texCood0"] = element.geometry.texCood0;
                }
                if (element.geometry.color) {
                  geometry["color"] = element.geometry.color;
                  geometry.colorStep = element.geometry.colorsStep
                }
                if (element.geometry.tangents) {
                  geometry["tangent"] = element.geometry.tangents;
                  // geometry["tangent1"] = element.geometry.tangents;
                }
                if (element.geometry.targets) {
                  geometry.morphTargets = element.geometry.morphTargets;
                }

                let standardMaterial = this.materialMap.get(element.material);
                if (!standardMaterial) {
                  standardMaterial = new StandardMaterial({ metallicRoughnessMap: null });
                }
                const meshCom = new Mesh({ geometry, material: standardMaterial });
                const primitive = new Object3D({ maxInstanceNum });
                primitive.addComponent(meshCom);
                if (maxInstanceNum > 1) {
                  for (let index = 0; index < instances.length; index++) {
                    const instanceData = instances[index]; //{position:[],scale:[],rotation:[]}
                    if (index == 0) {
                      //索引为0的时候应该是更改
                      const trans = primitive.trans.getInstance(0);
                      instanceData.position && (trans.position = instanceData.position);
                      instanceData.scale && (trans.scale = instanceData.scale);
                      instanceData.rotation && (trans.rotation = instanceData.rotation);
                      trans.applyMatrix4(element.worldMatrix);
                    } else {
                      //其他是增加
                      const trans = new Trans(instanceData);
                      trans.applyMatrix4(element.worldMatrix);
                      primitive.trans.add(trans);
                    }
                  }
                } else {
                  primitive.trans.applyMatrix4(element.worldMatrix);
                }

                root.add(primitive);
              }
              callback(root);
            } else {
              let root = new Object3D({ id });
              if (maxInstanceNum <= 1) {
                //非实例化
                root.trans.applyMatrix4(localMatrix);
              }
              this.materialMap = new Map();
              this.geometryMeshes = [];
              this.createMaterial(gltf, mipMap, bigTextureQuality);
              this.createGeometryMesh(gltf, id);
              let children = [];
              gltf.scenes[gltf.defaultScene].nodes.map(child => {
                let id = root.id + `${child}`;
                children.push(id);
                const node = this.parseNode(child, root, gltf, null, instances, maxInstanceNum);
                // root.add(node)
                // this.nodes.set(child, node);
              });
              // rootNode.children = children;
              if (gltf.animations && gltf.animations.length) {
                this.handleAnimation(gltf.animations, id);
              }
              callback(root);
              // root.update();
            }
            db.addPromise({ id: url, value: gltf });
          }
        );
      }
    } else {
      process({ url, type: "gltf", back, matrix: localMatrix, optimize, supportedFormatList },
        async message => {
          //todo 子线程处理完成后，执行主线程的操作
          // sRGB空间转为线性空间
          let gltf = message.data;
          console.log(gltf);
          // let id = fileName + `${gltf.defaultScene}` + randomString(4); //根节点id
          let id = fileName; //根节点id
          this.animations.set(id, []);
          this.skinAnmations.set(id, []);
          if (gltf.noAnimation && optimize) {
            this.createMaterial(gltf, mipMap, bigTextureQuality);
            const primitives = gltf.primitives;
            let meshes = [];
            const root = new Object3D({ id: id });
            for (let index = 0; index < primitives.length; index++) {
              const element = primitives[index];
              const geometry = new Geometry();
              if (element.geometry.position) {
                geometry["position"] = element.geometry.position;
                // geometry["position1"] = element.geometry.position;
              }
              if (element.geometry.indices) {
                geometry["indices"] = element.geometry.indices;
              }
              if (element.geometry.normal) {
                geometry["normal"] = element.geometry.normal;
                // geometry["normal1"] = element.geometry.normal;
              }
              if (element.geometry.texCood1) {
                geometry["texCood1"] = element.geometry.texCood1;
              }
              if (element.geometry.texCood0) {
                geometry["texCood0"] = element.geometry.texCood0;
              }
              if (element.geometry.color) {
                geometry["color"] = element.geometry.color;
                geometry.colorStep = element.geometry.colorsStep
              }
              if (element.geometry.tangents) {
                geometry["tangent"] = element.geometry.tangents;
                // geometry["tangent1"] = element.geometry.tangents;
              }
              if (element.geometry.targets) {
                geometry.morphTargets = element.geometry.morphTargets;
              }

              let standardMaterial = this.materialMap.get(element.material);
              if (!standardMaterial) {
                standardMaterial = new StandardMaterial({ metallicRoughnessMap: null });
              }
              const meshCom = new Mesh({ geometry, material: standardMaterial });
              const primitive = new Object3D({ maxInstanceNum });
              primitive.addComponent(meshCom);
              if (maxInstanceNum > 1) {
                for (let index = 0; index < instances.length; index++) {
                  const instanceData = instances[index]; //{position:[],scale:[],rotation:[]}
                  if (index == 0) {
                    //索引为0的时候应该是改
                    const trans = primitive.trans.getInstance(0);
                    instanceData.position && (trans.position = instanceData.position);
                    instanceData.scale && (trans.scale = instanceData.scale);
                    instanceData.rotation && (trans.rotation = instanceData.rotation);
                    trans.applyMatrix4(element.worldMatrix);
                  } else {
                    //其他是增加
                    const trans = new Trans(instanceData);
                    trans.applyMatrix4(element.worldMatrix);
                    primitive.trans.add(trans);
                  }
                }
              } else {
                primitive.trans.applyMatrix4(element.worldMatrix);
              }

              root.add(primitive);
            }
            callback(root);
          } else {
            let root = new Object3D({ id });
            if (maxInstanceNum <= 1) {
              //非实例化
              root.trans.applyMatrix4(localMatrix);
            }
            this.materialMap = new Map();
            this.geometryMeshes = [];
            this.createMaterial(gltf, mipMap, bigTextureQuality);
            this.createGeometryMesh(gltf, id);
            let children = [];
            gltf.scenes[gltf.defaultScene].nodes.map(child => {
              let id = root.id + `${child}`;
              children.push(id);
              const node = this.parseNode(child, root, gltf, null, instances, maxInstanceNum);
              // root.add(node)
              this.nodes.set(child, node);
            });
            // rootNode.children = children;
            if (gltf.animations && gltf.animations.length) {
              this.handleAnimation(gltf.animations, id);
            }
            callback(root);
            // root.update();
          }
        }
      );
    }
  }
  parseNode(_nodeIndex, parentNode, gltf, parentMat, instances, maxInstanceNum) {
    let _node = gltf.nodes[_nodeIndex];
    let id = parentNode.id + `_${_nodeIndex}`;
    let node = new Object3D({ id });
    node.nodeId = _nodeIndex; //节点id
    this.meshMap.set(id, node);
    node.parent = parentNode.id;
    this.nodes.set(_nodeIndex, node);
    let localMatrix = new Matrix4();
    if (_node?.matrix) {
      localMatrix = localMatrix.fromArray(_node.matrix);
    } else if (_node.translation || _node.rotation || _node.scale) {
      let translation = _node.translation ? new Vector3(..._node.translation) : new Vector3();
      let rotation = _node.rotation ? new Quaternion(..._node.rotation) : new Quaternion();
      let scale = _node.scale ? new Vector3(..._node.scale) : new Vector3(1, 1, 1);
      localMatrix.compose(translation, rotation, scale);
    }
    let worldMat = new Matrix4();
    if (maxInstanceNum <= 1) {
      //非实例化需要给每个object3d乘以矩阵
      node.trans.applyMatrix4(localMatrix);
    } else {
      if (parentMat) {
        worldMat = parentMat.clone().multiply(localMatrix);
      } else {
        worldMat = localMatrix;
      }
    }
    let skinObject = null;
    // 骨骼动画对象
    if (_node.skin != undefined) {
      skinObject = gltf.skins[_node.skin];
      node.skinObject = skinObject;
      // this.skinAnmations.get(group.id).push(node)
    }
    parentNode.add(node);
    const _mesh = _node.mesh;
    if (isNotBlank(_mesh)) {
      this.parseMesh(_mesh, gltf, node, worldMat, instances, maxInstanceNum);
    }
    if (_node.children) {
      _node.children.map(child => {
        this.parseNode(child, node, gltf, worldMat, instances, maxInstanceNum);
      });
    }

    return node;
  }

  parseMesh(meshIndex, gltf, parentNode, parentMat, instances, maxInstanceNum) {
    const meshObject = gltf.meshes[meshIndex];
    // parentNode.children = []
    meshObject.primitives.map((premitive, index) => {
      const id = parentNode.id + `_${meshIndex}` + `_${index}`;
      const mesh = this.parseGeometryMesh(meshIndex, index);
      if (this.boxEnable) {
        const boundingBox = mesh.geometry.boundingBox
        const max = new Vector3().fromArray(boundingBox.max)
        const maxWorld = max.applyMatrix4(parentNode.trans.matrix)
        const min = new Vector3().fromArray(boundingBox.min)
        const minWorld = min.applyMatrix4(parentNode.trans.matrix)
        const bbox = new Box3(minWorld, maxWorld)
        this.boundingBox = this.boundingBox.union(bbox)
      }
      let meshNode;
      if (maxInstanceNum <= 1) {
        meshNode = new Object3D({ id: id });
        meshNode.addComponent(mesh);
      } else {
        meshNode = new Object3D({ maxInstanceNum });
        meshNode.addComponent(mesh);
        if (instances.length > 0) {
          for (let index = 0; index < instances.length; index++) {
            //将需要实例化模型的每个mesh，乘以它的实例化矩阵
            const instanceData = instances[index]; //{position:[],scale:[],rotation:[]}
            if (index == 0) {
              const trans = meshNode.trans.getInstance(0);
              meshNode.trans.base = parentMat.clone();
              instanceData.position && (trans.position = instanceData.position);
              instanceData.scale && (trans.scale = instanceData.scale);
              instanceData.rotation && (trans.rotation = instanceData.rotation);
              trans.applyMatrix4(parentMat);
            } else {
              const trans = new Trans(instanceData);
              trans.applyMatrix4(parentMat);
              meshNode.trans.add(trans);
            }
          }
        } else {
          const trans = meshNode.trans.getInstance(0);
          meshNode.trans.base = parentMat.clone();
          trans.applyMatrix4(parentMat);
        }

      }

      this.meshMap.set(id, meshNode);
      meshNode.parent = parentNode.id;
      parentNode.add(meshNode);
      // for (const key in mesh) {
      //   if (key !== "primitives") {
      //     parentNode[key] = mesh[key];
      //   }
      // }
    });
  }
  createMaterial(gltf, mipMap, bigTextureQuality) {
    if (!gltf.materials) {
      return;
    }
    const materials = gltf.materials;
    materials.map((material, index) => {
      let { alphaMode, doubleSided, emissiveFactor, pbrMetallicRoughness, name, alphaCutoff } =
        material;
      let { baseColorFactor, metallicFactor, roughnessFactor } = pbrMetallicRoughness;
      const textureIndex = getTexturesObject(material);
      const {
        baseColorTexture,
        metallicRoughnessTexture,
        normalTexture,
        occlusionTexture,
        emissiveTexture,
      } = textureIndex;
      var mapUvTransform,
        emissiveMapUvTransform,
        metallicRoughnessMapUvTransform,
        normalMapUvTransform,
        aoMap_uvTransform;
      if (baseColorTexture?.extensions?.KHR_texture_transform) {
        mapUvTransform = this.generateUvTransform(
          baseColorTexture.extensions.KHR_texture_transform
        );
      }
      if (metallicRoughnessTexture?.extensions?.KHR_texture_transform) {
        metallicRoughnessMapUvTransform = this.generateUvTransform(
          metallicRoughnessTexture.extensions.KHR_texture_transform
        );
      }
      if (normalTexture?.extensions?.KHR_texture_transform) {
        normalMapUvTransform = this.generateUvTransform(
          normalTexture.extensions.KHR_texture_transform
        );
      }
      if (occlusionTexture?.extensions?.KHR_texture_transform) {
        aoMap_uvTransform = this.generateUvTransform(
          occlusionTexture.extensions.KHR_texture_transform
        );
      }
      if (emissiveTexture?.extensions?.KHR_texture_transform) {
        emissiveMapUvTransform = this.generateUvTransform(
          emissiveTexture.extensions.KHR_texture_transform
        );
      }
      let alphaTest = 0;
      let blend;
      let transparent = false;
      if (alphaMode === "BLEND") {
        blend = {
          alphaSrcFactor: "one",
          alphaDstFactor: "one",
          alphaOperation: "add",
          colorSrcFactor: "src-alpha",
          colorDstFactor: "one-minus-src-alpha",
          colorOperation: "add",
        };
        transparent = true;
      }
      if (alphaMode === "MASK" && !alphaCutoff) {
        alphaCutoff = 0.5;
      }
      const textureArray = gltf.images;
      let standardMaterial = new StandardMaterial({
        side: doubleSided ? "none" : null,
        name: material.name,
        color: baseColorFactor,
        alphaCutoff: alphaCutoff,
        alphaSrcFactor: blend?.alphaSrcFactor,
        alphaDstFactor: blend?.alphaDstFactor,
        alphaOperation: blend?.alphaOperation,
        colorSrcFactor: blend?.colorSrcFactor,
        colorDstFactor: blend?.colorDstFactor,
        colorOperation: blend?.colorOperation,
        metalness: metallicFactor,
        roughness: roughnessFactor,
        emissive: emissiveFactor,
        emissiveMap: emissiveTexture
          ? {
            sampler: emissiveTexture.sampler,
            url: emissiveTexture ? textureArray[emissiveTexture.source] : null,
            uvIndex: emissiveTexture?.texCoord || 0,
            uvTransform: emissiveMapUvTransform,
            isCache: false,
            mipMap: mipMap,
            bigTextureQuality: bigTextureQuality,
          }
          : undefined,

        metRougMap: metallicRoughnessTexture
          ? {
            sampler: metallicRoughnessTexture.sampler,
            url: metallicRoughnessTexture ? textureArray[metallicRoughnessTexture.source] : null,
            uvIndex: metallicRoughnessTexture?.texCoord || 0,
            uvTransform: metallicRoughnessMapUvTransform,
            isCache: false,
            mipMap: mipMap,
            bigTextureQuality: bigTextureQuality,
          }
          : undefined,
        normalMap: normalTexture
          ? {
            sampler: normalTexture.sampler,
            url: normalTexture ? textureArray[normalTexture.source] : null,
            uvIndex: normalTexture?.texCoord || 0,
            uvTransform: normalMapUvTransform,
            isCache: false,
            mipMap: mipMap,
            bigTextureQuality: bigTextureQuality,
          }
          : undefined,
        map: baseColorTexture
          ? {
            sampler: baseColorTexture.sampler,
            url: baseColorTexture ? textureArray[baseColorTexture.source] : null,
            uvIndex: baseColorTexture?.texCoord || 0,
            uvTransform: mapUvTransform,
            isCache: false,
            mipMap: mipMap,
            bigTextureQuality: bigTextureQuality,
          }
          : undefined,
        aoMap: occlusionTexture
          ? {
            sampler: occlusionTexture.sampler,
            url: occlusionTexture ? textureArray[occlusionTexture.source] : null,
            uvIndex: occlusionTexture?.texCoord || 0,
            uvTransform: aoMap_uvTransform,
            isCache: false,
            mipMap: mipMap,
            bigTextureQuality: bigTextureQuality,
          }
          : undefined,
        alphaCutoff: alphaCutoff,
        transparent: transparent,
      });
      this.materialMap.set(index, standardMaterial);
    });
  }
  createGeometryMesh(gltf, rootId) {
    const meshesData = gltf.meshes;
    for (let meshIndex = 0; meshIndex < meshesData.length; meshIndex++) {
      const meshData = meshesData[meshIndex];
      const name = meshData.name;
      const primitivesData = meshData.primitives;
      const weights = meshData.weights;
      this.geometryMeshes[meshIndex] = [];
      for (let primitiveIndex = 0; primitiveIndex < primitivesData.length; primitiveIndex++) {
        const primitiveData = primitivesData[primitiveIndex];
        const geometry = new Geometry({ name: name });
        const {
          boundingBox,
          indices,
          normals,
          positions,
          uv1s,
          uvs,
          vertexCount,
          colors,
          colorsStep,
          tangents,
          morphTargetTextureArray,
          morphTextureDepth,
          morphTextureWidth,
          morphTarget,
          joints0,
          weights0,
          joints1,
          weights1,
        } = primitiveData;
        let indicesNes;
        if (indices?.byteLength) {
          const TypedArrayConstructor = indices.constructor;
          if (!(vertexCount % 4 === 0)) {
            indicesNes = new TypedArrayConstructor(Math.ceil(vertexCount / 4) * 4);
            indicesNes.set(indices);
          } else {
            indicesNes = indices;
          }
        }
        geometry.boundingBox = boundingBox;
        if (positions) {
          geometry["position"] = positions;
          // if (gltf.isMorph) geometry["position1"] = positions;
        }
        if (indices) {
          geometry["indices"] = indicesNes;
        }
        if (normals) {
          geometry["normal"] = normals;
          // if (gltf.isMorph) geometry["normal1"] = normals;
        }
        if (uv1s) {
          geometry["texCood1"] = uv1s;
        }
        if (uvs) {
          geometry["texCood0"] = uvs;
        }
        if (colors) {
          geometry.colorStep = colorsStep
          geometry["color"] = colors;
        }
        if (tangents) {
          geometry["tangent"] = tangents;
          // if (gltf.isMorph) geometry["tangent1"] = tangents;
        }
        if (morphTargetTextureArray && morphTargetTextureArray.length > 0) {
          const gpuTexture = Engine.instance.device.createTexture({
            label: "yellow F on red",
            size: [morphTextureWidth, morphTextureWidth, morphTextureDepth],
            format: "rgba32float",
            usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,
          });
          // 创建命令缓冲区
          const commandEncoder = Engine.instance.device.createCommandEncoder();
          for (let index = 0; index < morphTargetTextureArray.length; index++) {
            const data = morphTargetTextureArray[index];
            const buffer = Engine.instance.device.createBuffer({
              size: data.byteLength,
              usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
            });
            Engine.instance.device.queue.writeBuffer(buffer, 0, data);
            commandEncoder.copyBufferToTexture(
              {
                buffer: buffer,
                bytesPerRow: morphTextureWidth * 4 * 4, // 每行的字节数
                rowsPerImage: morphTextureWidth, // 每张图片的行数
              },
              {
                texture: gpuTexture,
                origin: [0, 0, index],
              },
              [morphTextureWidth, morphTextureWidth]
            );
          }
          Engine.instance.device.queue.submit([commandEncoder.finish()]);
          // for (let index = 0; index < morphTargetTextureArray.length; index++) {
          //   const data = morphTargetTextureArray[index];
          //   // const offset = index * morphTextureWidth * morphTextureWidth * 4 * 4; // 设置偏移量
          //   Engine.instance.device.queue.writeTexture(
          //     {
          //       texture: gpuTexture,
          //       // origin:[0, 0, index]
          //     },
          //     data,
          //     {
          //       bytesPerRow: morphTextureWidth * 4*4,
          //       rowsPerImage: morphTextureWidth,
          //       // offset:offset
          //     },
          //     {
          //       width: morphTextureWidth,
          //       height: morphTextureWidth,
          //       depthOrArrayLayers: index,
          //     }
          //   );
          // }
          // Engine.instance.device.queue.writeTexture(
          //   { texture: gpuTexture },
          //   morphTargetTextureArray,
          //   { bytesPerRow: morphTextureWidth * 4*4 },
          //   { width: morphTextureWidth, height: morphTextureWidth }
          // );
          geometry.morphOffset = gpuTexture;
          geometry.morphWeightCount = weights.length;
          geometry.morphWeight = weights;
          geometry.morphPositionOffset = morphTarget.POSITION;
          geometry.morphNormalOffset = morphTarget.NORMAL;
          geometry.morphTangentOffset = morphTarget.TANGENT;
          // geometry.morphTarget = weights;
        }
        if (joints0) {
          // const buffer=joints0.buffer
          // let joints0Data=  new Uint32Array(buffer)
          geometry["joints0"] = joints0;
        }
        if (weights0) {
          geometry["weights0"] = weights0;
        }
        if (joints1) {
          geometry["joints1"] = joints1;
        }
        if (weights1) {
          geometry["weights1"] = weights1;
        }
        const material = this.parseMaterial(primitiveData);
        const randomStr = randomString(5)
        let mesh = new Mesh({ geometry, material, id: `${rootId}_${meshIndex}_${primitiveIndex}` + "mesh" + randomStr });
        this.geometryMeshes[meshIndex][primitiveIndex] = mesh;
      }
    }
  }
  parseGeometryMesh(meshIndex, premitiveIndex) {
    const geometry = this.geometryMeshes[meshIndex][premitiveIndex];
    return geometry;
  }

  parseMaterial(_mesh) {
    const { material } = _mesh;
    let standardMaterial;
    if (material !== undefined) {
      standardMaterial = this.materialMap.get(material);
    } else {
      standardMaterial = new StandardMaterial({ metallicRoughnessMap: null });
    }
    return standardMaterial;
  }

  jsToGl(array) {
    let tensor = new glMatrix.ARRAY_TYPE(array.length);
    for (let i = 0; i < array.length; ++i) {
      tensor[i] = array[i];
    }
    return tensor;
  }
  generateUvTransform(KHRTextureTransform) {
    let rotation = new Matrix3();
    let scale = new Matrix3();
    let translation = new Matrix3();
    if (KHRTextureTransform.rotation !== undefined) {
      const s = Math.sin(KHRTextureTransform.rotation);
      const c = Math.cos(KHRTextureTransform.rotation);

      rotation = rotation.set(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0);
    }

    if (KHRTextureTransform.scale !== undefined) {
      scale = scale.set(KHRTextureTransform.scale[0], 0, 0, 0, KHRTextureTransform.scale[1], 0, 0, 0, 1,);
    }

    if (KHRTextureTransform.offset !== undefined) {
      translation = translation.set(1, 0, 0, 0, 1, 0, KHRTextureTransform.offset[0], KHRTextureTransform.offset[1], 1);
    }

    let uvMatrix = new Matrix3();
    uvMatrix.multiplyMatrices(translation, rotation);
    uvMatrix.multiply(scale);
    return uvMatrix;
  }
  handleAnimation(animations, id) {
    animations.map(animation => {
      const animationObject = new Animation({ id: animation.name, keep: true, loop: 0 });
      const channels = animation.channels;
      channels.map(channel => {
        const time = channel.input;
        const value = channel.output;
        if (channel.path === "rotation" && channel.outPutType === "VEC4") {
          channel.path = "quaternion";
          channel.interpolation = "QUATLINEAR";
        }
        if (channel.path === "translation") {
          channel.path = "position";
        }
        const nodeObject3d = this.nodes.get(channel.node);
        if (!nodeObject3d) {
          return;
        }
        if (channel.path === "weights") {
          this.recurve(nodeObject3d, channel, animationObject);
        } else {
          const sampler = new Sampler(time, value, channel.interpolation, "none");
          const channelObject = new Channel(nodeObject3d.trans, channel.path);
          channelObject.add(sampler);
          animationObject.add(channelObject);
          // this.recurve(nodeObject3d, channel, animationObject)
        }
      });
      // aniMix.add(animationObject)
      // engine.registe.main
      Engine.instance.scene.addAnimation(animationObject);
      this.animations.get(id).push(animation.name);
    });
    const skinNodes = this.skinAnmations.get(id);
    if (skinNodes.length > 0) {
      for (let index = 0; index < skinNodes.length; index++) {
        const skinNode = skinNodes[index];
        aniMix.addSkin(skinNode);
      }
    }
  }
  recurve(nodeObject3d, channel, animationObject) {
    if (nodeObject3d.mesh) {
      const time = channel.input;
      const value = channel.output;
      const sampler = new Sampler(time, value, channel.interpolation, "none");
      const channelObject = new Channel(nodeObject3d.mesh.geometry, channel.path);
      channelObject.add(sampler);
      animationObject.add(channelObject);
    }
    if (nodeObject3d.children && nodeObject3d.children.length > 0) {
      for (let index = 0; index < nodeObject3d.children.length; index++) {
        const element = nodeObject3d.children[index];
        const entity = this.meshMap.get(element);
        this.recurve(entity, channel, animationObject);
      }
    }
  }
  destroy(object3d) {
    // 平铺没有动画
    if (Array.isArray(object3d)) {
      const element = object3d[0];
      const group = element.group;
      const groups = em.layers.get("default").groups;
      const gltfGroup = groups.get(group.id);
      gltfGroup.markDestroy = true;
      gltfGroup.destroy();
    } else {
      const group = object3d.group;
      const rootId = object3d.id;
      // 销毁动画
      const skinAnList = this.skinAnmations.get(rootId);
      if (skinAnList) {
        for (let index = 0; index < skinAnList.length; index++) {
          const skinNode = skinAnList[index];
          aniMix.removeSkin(skinNode.id);
        }
      }
      const anList = this.animations.get(rootId);
      if (anList) {
        for (let index = 0; index < anList.length; index++) {
          const an = anList[index];
          aniMix.remove(an);
        }
      }

      this.animations.delete(rootId);
      const groups = em.layers.get("default").groups;
      const gltfGroup = groups.get(group.id);
      gltfGroup.markDestroy = true;
      gltfGroup.destroy();
    }
  }
}
const tranverse = nodeObject3d => {
  if (!nodeObject3d) return;
  nodeObject3d.destroy();
  if (nodeObject3d.children && nodeObject3d.children.length > 0) {
    for (let index = 0; index < nodeObject3d.children.length; index++) {
      const element = nodeObject3d.children[index];
      const entity = em.get(element);
      tranverse(entity);
    }
  }
};
export { GLTFLoader };
